import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

class FixedAdaptiveWidthDropdown<T> extends StatefulWidget {
  final T? value;
  final List<T> items;
  final ValueChanged<T?> onChanged;
  final String? hint;
  final TextStyle? textStyle;
  final Color? backgroundColor;
  final Color? borderColor;
  final double? maxListHeight;
  final double padding;
  final Color? dividerColor;

  const FixedAdaptiveWidthDropdown({
    super.key,
    required this.value,
    required this.items,
    required this.onChanged,
    this.hint,
    this.textStyle,
    this.backgroundColor,
    this.borderColor,
    this.maxListHeight,
    this.padding = 3.0,
    this.dividerColor,
  });

  @override
  _FixedAdaptiveWidthDropdownState<T> createState() =>
      _FixedAdaptiveWidthDropdownState<T>();
}

class _FixedAdaptiveWidthDropdownState<T>
    extends State<FixedAdaptiveWidthDropdown<T>> {
  final GlobalKey _buttonKey = GlobalKey();
  final ScrollController _scrollController = ScrollController();
  final _defaultFontSize = 16.0;
  final _defaultFontColor = Colors.grey;
  OverlayEntry? _overlayEntry;
  bool _isOpen = false;
  double? _maxTextWidth;
  double? _maxTextHeight;
  double? _maxItemHeight;

  @override
  void didUpdateWidget(covariant FixedAdaptiveWidthDropdown<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    _removeOverlay();
    super.dispose();
    _scrollController.dispose();
  }

  void _calculateItemSize() {
    final RenderBox? renderBox =
        _buttonKey.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox == null || !renderBox.hasSize) return;

    final padding = EdgeInsets.all(widget.padding);
    final textStyle =
        widget.textStyle ??
        TextStyle(color: _defaultFontColor, fontSize: _defaultFontSize);

    final textPainter = TextPainter(textDirection: TextDirection.ltr);

    try {
      String longestText = '';
      for (var item in widget.items) {
        final text = item.toString();
        if (text.length > longestText.length) {
          longestText = text;
        }
      }
      textPainter.text = TextSpan(text: ' $longestText ', style: textStyle);
      textPainter.layout();
      double maxWidth = textPainter.width + padding.horizontal;
      final screenWidth = MediaQuery.of(context).size.width;
      final paragraphBuilder =
          ParagraphBuilder(
              ParagraphStyle(textDirection: TextDirection.ltr, maxLines: 2),
            )
            ..pushStyle(textStyle.getTextStyle())
            ..addText('换行\n内容');

      final paragraph = paragraphBuilder.build();
      paragraph.layout(ParagraphConstraints(width: double.infinity));

      _maxTextWidth = max(
        renderBox.size.width,
        maxWidth > screenWidth ? screenWidth : maxWidth,
      );
      _maxTextHeight = paragraph.height + padding.vertical;
      _maxItemHeight = _maxTextHeight! + padding.vertical * 2 + 1;
    } catch (e) {
      _maxTextWidth = MediaQuery.of(context).size.width * 0.8;
    }
  }

  void _removeOverlay() {
    if (_overlayEntry != null) {
      _overlayEntry!.remove();
      _overlayEntry = null;
    }
    if (mounted && _isOpen) {
      setState(() {
        _isOpen = false;
      });
    }
  }

  void _toggleOverlay() {
    if (_isOpen) {
      _removeOverlay();
    } else {
      if (widget.items.isEmpty) {
        return;
      }
      _showOverlay();
    }
  }

  void _showOverlay() {
    _calculateItemSize();

    final RenderBox? renderBox =
        _buttonKey.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox == null || !renderBox.hasSize) return;

    final buttonSize = renderBox.size;
    final buttonOffset = renderBox.localToGlobal(Offset.zero);
    final screenSize = MediaQuery.of(context).size;
    final maxHeight = widget.maxListHeight ?? screenSize.height * 0.85;

    final spaceBelow = screenSize.height - buttonOffset.dy - buttonSize.height;
    final spaceAbove = buttonOffset.dy;
    final showBelow = spaceBelow >= maxHeight || spaceBelow > spaceAbove;

    final buttonCenterX = buttonOffset.dx + buttonSize.width / 2.0;
    final listLeft = buttonCenterX - _maxTextWidth! / 2.0;
    final listRight = buttonCenterX + _maxTextWidth! / 2.0;

    final adjustedLeft = listLeft < 0
        ? 0.0
        : listRight > screenSize.width
        ? screenSize.width - _maxTextWidth!
        : listLeft;

    _overlayEntry = OverlayEntry(
      builder: (context) {
        return Stack(
          children: [
            Positioned.fill(
              child: GestureDetector(
                onTap: _removeOverlay,
                behavior: HitTestBehavior.translucent,
                child: Container(color: Colors.transparent),
              ),
            ),
            Positioned(
              left: adjustedLeft,
              top: showBelow ? buttonOffset.dy + buttonSize.height : null,
              bottom: showBelow ? null : screenSize.height - buttonOffset.dy,
              child: Material(
                elevation: 4.0,
                child: Container(
                  width: _maxTextWidth,
                  constraints: BoxConstraints(maxHeight: maxHeight),
                  decoration: BoxDecoration(
                    color: widget.backgroundColor ?? Colors.black,
                    borderRadius: BorderRadius.circular(4.0),
                    border: Border.all(
                      color: widget.borderColor ?? Colors.grey[600]!,
                    ),
                  ),
                  child: ListView.separated(
                    controller: _scrollController,
                    shrinkWrap: true,
                    padding: EdgeInsets.zero,
                    itemCount: widget.items.length,
                    separatorBuilder: (context, index) => Divider(
                      height: 1,
                      color: widget.dividerColor ?? Colors.grey[700],
                      thickness: 0.5,
                    ),
                    itemBuilder: (context, index) {
                      final item = widget.items[index];
                      return InkWell(
                        onTap: () {
                          widget.onChanged(item);
                          _removeOverlay();
                        },
                        child: Container(
                          width: double.infinity,
                          padding: EdgeInsets.symmetric(
                            horizontal: widget.padding,
                            vertical: 6.0,
                          ),
                          color: item == widget.value
                              ? Colors.blue[700]
                              : Colors.transparent,
                          child: Container(
                            height: _maxTextHeight,
                            alignment: Alignment.centerLeft,
                            child: Text(
                              item.toString(),
                              style:
                                  widget.textStyle ??
                                  TextStyle(
                                    color: _defaultFontColor,
                                    fontSize: _defaultFontSize,
                                  ),
                              overflow: TextOverflow.ellipsis,
                              maxLines: 2,
                            ),
                          ),
                        ),
                      );
                    },
                  ),
                ),
              ),
            ),
          ],
        );
      },
    );
    Overlay.of(context).insert(_overlayEntry!);
    if (mounted && !_isOpen) {
      setState(() {
        _isOpen = true;
      });
    }
    WidgetsBinding.instance.addPostFrameCallback((_) {
      try {
        var index = widget.items.indexOf(widget.value as T);
        _scrollController.jumpTo(index * _maxItemHeight!);
      } catch (e) {
        debugPrint('scrollController.jumpTo error:$e');
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: GestureDetector(
        key: _buttonKey,
        onTap: _toggleOverlay,
        child: Container(
          decoration: BoxDecoration(
            color: widget.backgroundColor ?? Colors.black,
            borderRadius: BorderRadius.circular(4.0),
            border: Border.all(color: widget.borderColor ?? Colors.grey[600]!),
          ),
          padding: EdgeInsets.symmetric(horizontal: 0.0, vertical: 3.0),
          child: Row(
            children: [
              Expanded(
                child: Text(
                  widget.value?.toString() ?? widget.hint ?? '请选择',
                  style:
                      widget.textStyle ??
                      TextStyle(
                        color: _defaultFontColor,
                        fontSize: _defaultFontSize,
                      ),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
              Icon(
                _isOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down,
                color: Colors.grey[400],
                size: 20,
              ),
            ],
          ),
        ),
      ),
    );
  }
}
